package com.lws.hellotoken;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;

public class ThreeDes {

    public static final String DES = "DESede";
    public static final String CHARACTER_ENCODING = "UTF-8";
    public static final String TRANSFORMATION = "DESede/CBC/PKCS5Padding";//拦截
    public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    // CBC方式的初始化向量
    private static final IvParameterSpec IVPARAM = new IvParameterSpec(new byte[]{93, 81, 122, 33, 47, 50, 17, 103});

    public static void main(String[] args) {
        String token = createToken("192.168.20.176", "kentop", "kentop", "secret");
        String[] secrets = authToken(token, "secret");
        System.out.println(Arrays.toString(secrets));
    }

    /**
     * 检查密钥长度,如不足24位,则加0x00补齐
     *
     * @param keyString
     * @return
     */
    private static byte[] getKeyBytes(String keyString) {
        byte[] b = new byte[24];
        byte[] key = keyString.getBytes();
        int count = keyString.getBytes().length;
        for (int i = 0; i < count; i++) {
            b[i] = key[i];
        }
        for (int i = count; i < 24; i++) {
            b[i] = 0x00;
        }
        return b;
    }

    /***
     * 加密
     *
     * @param text
     * @return
     */
    private static String encrypt(String text, String secret) {
        String encode = "";
        try {
            // 24字节密钥key,3倍DES密钥长度
            byte[] tripleKey = getKeyBytes(secret);

            // 生成密钥
            SecretKey secretKey = new SecretKeySpec(tripleKey, DES);

            // 初始化密文书写
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, IVPARAM);

            // 加密
            byte[] encriptText = cipher.doFinal(text.getBytes(CHARACTER_ENCODING));

            encode = new BASE64Encoder().encode(encriptText);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encode;
    }

    /***
     * 解密
     *
     * @param text
     * @return
     */
    private static String decrypt(String text, String secret) {
        String decode = null;
        try {
            byte[] auth = new BASE64Decoder().decodeBuffer(text);

            // 24字节密钥key,3倍DES密钥长度
            byte[] tripleKey = getKeyBytes(secret);

            // 生成密钥
            SecretKey secretKey = new SecretKeySpec(tripleKey, DES);

            // 初始化密文书写
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, IVPARAM);

            // 解密
            decode = new String(cipher.doFinal(auth), CHARACTER_ENCODING);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return decode;
    }

    /**
     * 认证码
     *
     * @return
     * @throws Exception
     */
    public static String createToken(String host, String apId,
                                     String apName, String secret) {
        String token = null;
        try {
            StringBuilder orgToken = new StringBuilder();
            orgToken.append("Host=").append(host)
                    .append(";QRAPID=").append(apId)
                    .append(";QRAPName=").append(apName)
                    .append(";CurrentTime=").append(DATE_FORMAT.format(new Date()));

            token = encrypt(orgToken.toString(), secret);
        } catch (Exception ex) {//
            ex.printStackTrace();
        }
        return token;
    }

    /***
     * 验证认证码
     *
     * @param token
     * @return
     */
    public static String[] authToken(String token, String secret) {
        // 输出参数
        String[] str = new String[2];
        // 拆分认证码验证
        try {
            String orgToken = decrypt(token, secret);

            // 拆分值并存入Map中
            HashMap<String, String> map = new HashMap<String, String>();
            String[] tokenValue = orgToken.split(";");
            for (int i = 0; i < tokenValue.length; i++) {
                String[] value = tokenValue[i].split("=");
                map.put(value[0], value[1]);
            }

            // 判断值是否相等
            if ("192.168.20.176".equals(map.get("Host"))
                    && "kentop".equals(map.get("QRAPID"))
                    && "kentop".equals(map.get("QRAPName"))) {
                Date now = new Date();
                Date timeStamp = DATE_FORMAT.parse(map.get("CurrentTime"));
                long between = Math.abs(now.getTime() - timeStamp.getTime()) / 1000;// 除以1000是为了转换成秒

                // 比较两者差是否超过3分钟
                if (between >= 180) {
                    str[0] = "3";
                    str[1] = "验证失败,超过当前时间3分钟!";
                } else {
                    str[0] = "0";
                    str[1] = "验证成功!";
                }
            } else {
                str[0] = "3";
                str[1] = "验证失败,数据错误!";
            }
        } catch (Exception e) {
            str[0] = "3";
            str[1] = "验证失败,出异常!";
            e.printStackTrace();
        }
        return str;
    }

}
